package com.fulihui.wgj.service.platform;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.fulihui.common.builder.rpc.RpcResultBuilder;
import com.fulihui.common.constants.OpenMpConstants;
import com.fulihui.common.conv.BeanConv;
import com.fulihui.common.enums.PlatformStatusEnum;
import com.fulihui.common.enums.WxSystemConfigKeyEnum;
import com.fulihui.common.error.Errors;
import com.fulihui.common.error.InvokeServiceException;
import com.fulihui.common.result.rpc.BaseResult;
import com.fulihui.common.result.rpc.SimpleResult;
import com.fulihui.common.util.ConditionValidator;
import com.fulihui.common.util.PlatformUtil;
import com.fulihui.common.util.WxDateUtil;
import com.fulihui.weixinsdk.WeixinSDK;
import com.fulihui.weixinsdk.model.AuthorizationInfo;
import com.fulihui.weixinsdk.request.ApiQueryAuthRequest;
import com.fulihui.weixinsdk.request.statistics.UserCumulateRequest;
import com.fulihui.weixinsdk.request.statistics.UserSummaryRequest;
import com.fulihui.weixinsdk.result.ApiQueryAuthResult;
import com.fulihui.weixinsdk.result.statistics.UserCumulateResult;
import com.fulihui.weixinsdk.result.statistics.UserSummaryResult;
import com.fulihui.wgj.config.properties.AppProps;
import com.fulihui.wgj.dal.mybatis.domain.WxPlatform;
import com.fulihui.wgj.dal.mybatis.domain.WxSystemConfig;
import com.fulihui.wgj.dal.mybatis.repository.WxPlatformRepository;
import com.fulihui.wgj.dal.mybatis.repository.WxSystemConfigRepository;
import com.fulihui.wgj.facade.dto.FuncInfoDTO;
import com.fulihui.wgj.facade.dto.WxPlatformDTO;
import com.fulihui.wgj.facade.dto.WxUserCumulateDTO;
import com.fulihui.wgj.facade.dto.WxUserSummaryDTO;
import com.fulihui.wgj.facade.request.platform.WxPlatformLoginPageRequest;
import com.fulihui.wgj.facade.request.platform.WxPlatformPageRequest;
import com.fulihui.wgj.facade.request.platform.WxPlatformQueryRequest;
import com.fulihui.wgj.facade.result.platform.WxPlatformPageResult;
import com.fulihui.wgj.facade.result.platform.WxPlatformQueryResult;
import com.fulihui.wgj.facade.service.platform.WxPlatformService;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.text.MessageFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author wang_wx
 * @date 2018-06-22
 */
@Component
@Service(interfaceClass = WxPlatformService.class, version = "1.0.0")
public class WxPlatformServiceImpl implements WxPlatformService {

    private static final Logger LOGGER = LoggerFactory.getLogger(WxPlatformServiceImpl.class);

    @Autowired
    WxPlatformRepository wxPlatformRepository;

    @Autowired
    PlatformUtil platformUtil;

    @Autowired
    WxSystemConfigRepository wxSystemConfigRepository;

    @Autowired
    AppProps appProps;

    @Autowired
    WeixinSDK weixinSDK;

    @Override
    public WxPlatformPageResult queryWxPlatformPage(WxPlatformPageRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        PageInfo<WxPlatform> wxPlatformPageInfo = wxPlatformRepository.queryPageListByWhere2Example(request);
        long total = wxPlatformPageInfo.getTotal();
        WxPlatformPageResult wxPlatformPageResult = RpcResultBuilder.succPageResult(WxPlatformPageResult.class, wxPlatformPageInfo.getPageNum(), wxPlatformPageInfo.getPageSize(), (int) total);
        if (total > 0) {
            wxPlatformPageResult.setValue(BeanConv.copy(wxPlatformPageInfo.getList(), WxPlatformDTO.class));
        }
        return wxPlatformPageResult;
    }

    @Override
    public WxPlatformPageResult queryWxPlatformPageHasWxUser(WxPlatformLoginPageRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        PageInfo<WxPlatform> wxPlatformPageInfo = wxPlatformRepository.queryPageListByLoginUserId(request);
        long total = wxPlatformPageInfo.getTotal();
        List<WxPlatform> list = wxPlatformPageInfo.getList();
        WxPlatformPageResult wxPlatformPageResult = RpcResultBuilder.succPageResult(WxPlatformPageResult.class, wxPlatformPageInfo.getPageNum(), wxPlatformPageInfo.getPageSize(), Math.toIntExact(total));
        if (total > 0) {
            List<WxPlatformDTO> wxPlatformDTOS = BeanConv.copy(list, WxPlatformDTO.class);
            wxPlatformDTOS.stream().filter(wxPlatformDTO -> !wxPlatformDTO.getStatus().equals(PlatformStatusEnum.cancel))
                    .forEach(wxPlatformDTO -> {
                        // 获取用户统计数据
                        String appId = wxPlatformDTO.getAppId();
                        WxUserSummaryDTO userSummaryDTO = getUserSummary(appId);
                        wxPlatformDTO.setWxUserSummaryDTO(userSummaryDTO);
                        WxUserCumulateDTO wxUserCumulateDTO = getUserCumulate(appId);
                        wxPlatformDTO.setWxUserCumulateDTO(wxUserCumulateDTO);
                    });
            wxPlatformPageResult.setValue(wxPlatformDTOS);
        }
        return wxPlatformPageResult;
    }

    /**
     * 获取累计用户数据
     *
     * @param appId 公众号appId
     * @return
     */
    private WxUserCumulateDTO getUserCumulate(String appId) {
        WxUserCumulateDTO wxUserCumulateDTO = new WxUserCumulateDTO();
        String yesterdayStr = WxDateUtil.getYesterdayStr();
        if (StringUtils.isNotBlank(appId)) {
            AtomicReference<Long> cumulateUserCount = new AtomicReference<>(0L);
            String cache = platformUtil.get(appId);
            if (StringUtils.isNotBlank(cache)) {
                UserCumulateRequest cumulateRequest = new UserCumulateRequest();
                cumulateRequest.setAccess_token(cache);
                cumulateRequest.setBegin_date(yesterdayStr);
                cumulateRequest.setEnd_date(yesterdayStr);
                UserCumulateResult userCumulateResult = null;
                try {
                    userCumulateResult = weixinSDK.invokeService(cumulateRequest);
                } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                }
                if (userCumulateResult != null
                        && !CollectionUtils.isEmpty(userCumulateResult.getList())) {
                    userCumulateResult.getList().forEach(userCumulateData -> {
                        String cumulateUser = userCumulateData.getCumulate_user();
                        if (StringUtils.isNotBlank(cumulateUser)) {
                            cumulateUserCount.updateAndGet(v -> v + Long.valueOf(cumulateUser));
                        }
                    });
                }
            }
            wxUserCumulateDTO.setCumulateUser(cumulateUserCount.get() == 0L ? "0" : MessageFormat.format("{0}", cumulateUserCount.get()));
            return wxUserCumulateDTO;
        }
        return null;
    }

    /**
     * 获取用户增减数据
     *
     * @param appId 公众号appId
     * @return
     */
    private WxUserSummaryDTO getUserSummary(String appId) {
        WxUserSummaryDTO wxUserSummaryDTO = new WxUserSummaryDTO();
        String yesterdayStr = WxDateUtil.getYesterdayStr();
        if (StringUtils.isNotBlank(appId)) {
            AtomicReference<Long> newUserCount = new AtomicReference<>(0L);
            AtomicReference<Long> cancelUserCount = new AtomicReference<>(0L);
            String cache = platformUtil.get(appId);
            if (StringUtils.isNotBlank(cache)) {
                UserSummaryRequest summaryRequest = new UserSummaryRequest();
                summaryRequest.setAccess_token(cache);
                summaryRequest.setBegin_date(yesterdayStr);
                summaryRequest.setEnd_date(yesterdayStr);
                UserSummaryResult userSummaryResult = null;
                try {
                    userSummaryResult = weixinSDK.invokeService(summaryRequest);
                } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                }
                if (userSummaryResult != null
                        && !CollectionUtils.isEmpty(userSummaryResult.getList())) {
                    userSummaryResult.getList().forEach(userSummaryData -> {
                        //取关
                        String cancelUser = userSummaryData.getCancel_user();
                        //新增
                        String newUser = userSummaryData.getNew_user();
                        if (StringUtils.isNotBlank(newUser)) {
                            newUserCount.updateAndGet(v -> v + Long.valueOf(newUser));
                        }
                        if (StringUtils.isNotBlank(cancelUser)) {
                            cancelUserCount.updateAndGet(v -> v + Long.valueOf(cancelUser));
                        }
                    });
                }
            }
            wxUserSummaryDTO.setCanceUuser(cancelUserCount.get() == 0L ? "0" : MessageFormat.format("{0}", cancelUserCount.get()));
            wxUserSummaryDTO.setNewUser(newUserCount.get() == 0L ? "0" : MessageFormat.format("{0}", newUserCount.get()));
            Long netGrowth;
//            if (newUserCount.get() > cancelUserCount.get()) {
                netGrowth = newUserCount.get() - cancelUserCount.get();
//            }
            wxUserSummaryDTO.setNetGrowth(netGrowth == 0L ? "0" : MessageFormat.format("{0}", netGrowth));
            return wxUserSummaryDTO;
        }
        return null;
    }

    @Override
    public BaseResult authorized(String authorizationCode) {
        AuthorizationInfo info = getAuthorizationInfo(authorizationCode);
        platformUtil.set(info.getAuthorizer_appid(), info.getAuthorizer_access_token());
        return RpcResultBuilder.succ();
    }

    @Override
    public BaseResult unauthorized(String appId) {
        WxPlatform platform = new WxPlatform();
        platform.setAppId(appId);
        platform.setStatus(PlatformStatusEnum.cancel.getCode());
        int i = wxPlatformRepository.updateWxPlatformByAppId(platform);
        if (i > 0) {
            platformUtil.remove(platform.getAppId());
            return RpcResultBuilder.succ();
        } else {
            return RpcResultBuilder.fail(Errors.Commons.UPDATE_FAILED);
        }
    }

    @Override
    public BaseResult updateAuthorized(String authorizationCode) {
        AuthorizationInfo info = getAuthorizationInfo(authorizationCode);

        WxPlatform platform = new WxPlatform();
        platform.setAppId(info.getAuthorizer_appid());

        List<FuncInfoDTO> funcInfoList = new LinkedList<>();
        info.getFunc_info().forEach(f -> {
            FuncInfoDTO funcInfoDTO = new FuncInfoDTO();
            funcInfoDTO.setId(f.getFuncscope_category().getId());
//            funcInfoDTO.setName(FUNC_INFO_ZH[funcInfoDTO.getId() - 1]);
            funcInfoList.add(funcInfoDTO);
        });
        platform.setFuncInfo(JSON.toJSONString(funcInfoList));
        platform.setAuthorizerAccessToken(info.getAuthorizer_access_token());
        platform.setAuthorizerRefreshToken(info.getAuthorizer_refresh_token());
        platform.setGmtModified(new Date());

        int i = wxPlatformRepository.updateWxPlatformByAppId(platform);
        if (i > 0) {
            platformUtil.set(info.getAuthorizer_appid(), info.getAuthorizer_access_token());
            return RpcResultBuilder.succ();
        } else {
            return RpcResultBuilder.fail(Errors.Commons.UPDATE_FAILED);
        }
    }

    /**
     * 刷新Token
     *
     * @param appId
     * @param token
     * @return
     */
    @Override
    public BaseResult updateToken(String appId, String token, String refreshToken) {
        WxPlatform platform = new WxPlatform();
        platform.setAppId(appId);
        platform.setAuthorizerAccessToken(token);
        platform.setAuthorizerRefreshToken(refreshToken);
        platform.setTokenRefreshTime(new Date(System.currentTimeMillis()));

        int i = wxPlatformRepository.updateWxPlatformByAppId(platform);

        if (i > 0) {
            platformUtil.set(appId, token);
            return RpcResultBuilder.succ();
        } else {
            return RpcResultBuilder.fail(Errors.Commons.UPDATE_FAILED);
        }
    }

    @Override
    public SimpleResult<List<WxPlatformDTO>> queryUsefulPlatform() {
        List<WxPlatform> wxPlatforms = wxPlatformRepository.selectWxPlatformsStatusNormal();
        //返回对象
        if (!CollectionUtils.isEmpty(wxPlatforms)) {
            return RpcResultBuilder.succSimple(BeanConv.copy(wxPlatforms, WxPlatformDTO.class));
        }
        return RpcResultBuilder.succSimple(null);
    }

    /**
     * 获取公众号授权信息
     *
     * @param authorizationCode 授权码
     * @return
     */
    private AuthorizationInfo getAuthorizationInfo(String authorizationCode) {
        WxSystemConfig wxSystemConfig = new WxSystemConfig();
        wxSystemConfig.setCode(WxSystemConfigKeyEnum.component_access_token.getCode());
        WxSystemConfig tokenInfo = wxSystemConfigRepository.queryOne(wxSystemConfig);
        Date current = new Date(System.currentTimeMillis());
        if (tokenExpire(current, tokenInfo.getGmtModified())) {
            LOGGER.warn("component_access_token已经过期");
            return null;
        }
        ApiQueryAuthRequest queryAuthRequest = new ApiQueryAuthRequest();
        queryAuthRequest.setComponent_appid(appProps.getAppId());
        queryAuthRequest.setComponent_access_token(tokenInfo.getDescript());
        queryAuthRequest.setAuthorization_code(authorizationCode);

        ApiQueryAuthResult queryAuthResult = weixinSDK.invokeService(queryAuthRequest);
        AuthorizationInfo info = queryAuthResult.getAuthorization_info();
        return info;
    }

    /**
     * 判断token是否过期
     *
     * @param current
     * @param conpare
     * @return
     */
    private boolean tokenExpire(Date current, Date conpare) {
        return ((current.getTime() - conpare.getTime()) >= OpenMpConstants.TOKEN_EXPIRATION_TIME);
    }

    @Override
    public WxPlatformQueryResult queryWxPlatform(WxPlatformQueryRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        WxPlatformQueryResult result = RpcResultBuilder.succ(WxPlatformQueryResult.class);
        if (StringUtils.isNotBlank(request.getAppId())) {
            //根据appId获取指定的公众号信息
            List<WxPlatformDTO> wxPlatformDTOS = wxPlatformRepository.queryWxPlatformByAppId(request.getAppId());
            result.setValue(wxPlatformDTOS);
        } else {
            if (StringUtils.isNotBlank(request.getLoginId())) {
                result.setValue(wxPlatformRepository.queryWxPlatformsByLoginUserId(request.getLoginId()));
            }
        }
        return result;
    }

    @Override
    public SimpleResult<String> queryTokenFromRedis(String appId) {
        if (StringUtils.isNotBlank(appId)) {
            String token = platformUtil.get(appId);
            LOGGER.info("token = {}", token);
            return RpcResultBuilder.succSimple(token);
        }
        return RpcResultBuilder.failSimple(Errors.Commons.REQUEST_PARAMETER_ERROR);
    }
}
